﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using System.Security.Permissions;
using System.Text.RegularExpressions;
using System.Collections;
using System.Web.UI;
using System.Collections.Specialized;
using System.IO;

namespace JQuery.Net
{
    /// <summary>
    /// 
    /// </summary>
    /// <remarks>
    /// microsoft can take credit for this one if they would use public constructors this would not be neccesary.
    /// not we are avoiding the use of view state so the reliance on the state bag will be removed.
    /// </remarks>
    [AspNetHostingPermission(SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
    public class CssStyleCollection
    {
        private static readonly object @lock = new object();
        private static readonly Regex styleRegex = new Regex(
            "\\G(\\s*(;\\s*)*" +        // match leading semicolons and spaces
            "(?<stylename>[^:]+?)" +    // match stylename - chars up to the semicolon
            "\\s*:\\s*" +               // spaces, then the colon, then more spaces
            "(?<styleval>[^;]*)" +      // now match styleval
            ")*\\s*(;\\s*)*$",          // match a trailing semicolon and trailing spaces
            RegexOptions.Singleline |
            RegexOptions.Multiline |
            RegexOptions.ExplicitCapture |
            RegexOptions.Compiled);

        private IDictionary table;

        private string style;

        #region constructors
        public CssStyleCollection()
        {
        }
        #endregion

        #region indexers
        public string this[string key]
        {
            get
            {
                if (table == null)
                    Parse();

                string value = (string)table[key];

                return value;
            }
            set
            {
                Add(key, value);
            }
        }
        
        #endregion

        #region properties
        public int Count
        {
            get
            {
                if (table == null)
                    Parse();

                return table.Count;
            }
        }

        public string Value
        {
            get
            {
                if (table == null)
                {
                    lock (@lock)
                    {
                        if (table == null)
                        {
                            Parse();
                        }
                    }
                }

                style = Build();

                return style;
            }
            set
            {
                Clear();

                lock (@lock)
                {
                    style = value;
                }
            }
        }

        public ICollection Keys
        {
            get
            {
                if (table == null)
                    Parse();

                return table.Keys;
            }
        }
        #endregion

        #region methods
        public void Add(string key, string value)
        {
            if (String.IsNullOrEmpty(key))
            {
                throw new ArgumentNullException("key");
            }

            if (table == null)
                Parse();

            table[key] = value;
        }

        public void Remove(string key)
        {
            if (String.IsNullOrEmpty(key))
            {
                throw new ArgumentNullException("key");
            }

            if (table == null)
                Parse();

            if (table.Contains(key))
                table.Remove(key);
        }

        public void Clear()
        {
            table = null;
        }

        public void Render(StringWriter oWriter)
        {
            if (table != null && table.Count > 0)
            {
                foreach (DictionaryEntry entry in table)
                {
                    oWriter.Write(String.Format("{0}: {1}; ", entry.Key, entry.Value));
                }
            }
        }

        public void Render(HtmlTextWriter oWriter)
        {
            if (table != null && table.Count > 0)
            {
                foreach (DictionaryEntry entry in table)
                {
                    oWriter.AddStyleAttribute((string)entry.Key, (string)entry.Value);
                }
            }
        }

        private string Build()
        {
            if (table == null || table.Count == 0)
                return String.Empty;

            StringBuilder oResult = new StringBuilder();

            using (StringWriter oWriter = new StringWriter(oResult))
            {
                Render(oWriter);
            }

            return oResult.ToString().Trim();
        }

        private void Parse()
        {
            table = new HybridDictionary(false);

            if (style.IsNotNullOrEmpty())
            {
                Match oMatch;

                if ((oMatch = styleRegex.Match(style, 0)).Success)
                {
                    CaptureCollection stylenames = oMatch.Groups["stylename"].Captures;
                    CaptureCollection stylevalues = oMatch.Groups["styleval"].Captures;

                    for (int i = 0; i < stylenames.Count; i++)
                    {
                        String styleName = stylenames[i].ToString();
                        String styleValue = stylevalues[i].ToString();

                        table[styleName] = styleValue;
                    }
                }
            }
        }
        #endregion
    }
}
